package auction.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

import auction.domain.Auction;
import auction.domain.User;

public class ClientThread extends Thread {
	private Socket socket;

	private PrintWriter out;

	private BufferedReader in;

	private String threaduser;

	private int clientPort;
	
	private String command;

	public ClientThread(Socket socket) throws IOException {
		this.socket = socket;
		
		try {
			out = new PrintWriter(socket.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(socket
					.getInputStream()));

			
			String inputString = in.readLine();
			
			
			if (inputString == null) {
				throw new IOException("Client disconnected before identifying.");
			}
			String[] input = inputString.split(";");
			if (input.length != 2 ) {
				throw new IOException("Invalid client identification");
			}
			
			command = input[0];
			clientPort = Integer.parseInt(input[1]);

		} catch (IOException e) {
			cleanUp();
			throw e;
		}
		
		System.out.println("New Client. Port: " + clientPort);

		
	}

	public void run() {
		String username = "";
		String temp="";
		try {
			
			do  {
			
				//login
				if(command.startsWith("!login")){	
					if(command.length()>7){
				
						username = command.substring(7, command.length());			
						
						if (threaduser == null)
						{
								threaduser = username; //if no user is logged in on this client, set the user for this thread
							
							if (Server.userLoggedIn(username)) {
								send("User "+username+" is already logged in ");
								threaduser = null;
								
							}
							else{
								
								if(Server.usernameExists(username))
									Server.setLoggedIn(username);//if user already exists, only the boolean is set true
								else
									Server.addUser(new User(username,clientPort,true));//new user added to userslist
								
							    send("Successfully logged in as "+username+"!");
							}				
						}
						else {
							if(username.equals(threaduser))
								send("You are already logged in!");
							else
								send("There is already another user logged in on this Client!");
						}
					}
					else 
						send("Usage: !login <username>");
						
				} 				
				
				//logout
				else if (command.equals("!logout")) {						
						if (threaduser!=null){
						
								username = threaduser;
								//Server.updateLoggedIn(username, false);
								
								Server.logoutUser(username);
								this.threaduser = null; //set null because nobody is logged in on this client anymore
								send("Successfully logged out as "+username+"!");							
						}
						else
							send("You have to log in first!");
					
				}
				
				//end
				if (command.equals("") || command.equals("!end")) {
					if (threaduser!=null){
						
						username = threaduser;						
						Server.logoutUser(username); //logout user if terminated
												
					}
					send("break");
					Server.removeClient(this);
				
				}
				
				//list
				else if (command.equals("!list")) {
						send("!list" + Server.getAuctionList()); 						
				} 
				
				//create
				else if (command.startsWith("!create")) {					
					if(threaduser == null)
						send("You have to log in first!");
					else{
						if(command.length()>8)
						{
							
							
							String[] s = command.substring(8).split(" ");
							
							/* check input */
							boolean correctArgs =  s[0].matches("[0-9]+");
							int time = 0;
							

							if (correctArgs) {
							
								time = Integer.valueOf(s[0]); //milliseconds
								time = time*1000; //seconds
								Date current = new Date();
								int id = Server.getNextAuctionId();
								String description = command.substring(8+s[0].length()+1);
								Date end = new Date(current.getTime()+time);
								
								SimpleDateFormat formater = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss z");						   
								
								Server.createAuction(new Auction(id,description,threaduser,formater.format(end)), time);
								
								send("An auction '"+description+"' with id "+id+" has been created and will end on "+ formater.format(end) ); 					
							
							}
							else 
								send("Usage: !create <duration-in-seconds> <description> - the duration has to be a number! ");										
						}
						else
							send("Usage: !create <duration-in-seconds> <description>");
					}
				}
				
				//bid
				else if (command.startsWith("!bid")){
					if(threaduser == null)
						send("You have to log in first!");
					else{
						if(command.length()>5)
						{
							String[] s = command.substring(5).split(" ");
							
							/* check input */
							boolean correctArgs = s.length == 2 && s[0].matches("[0-9]+") && s[1].matches("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?");
							int id = 0;
							double amount = 0;

							if (correctArgs) {
								 id = Integer.valueOf(s[0]);
								 amount = Double.valueOf(s[1]); 
								 

								String ret = Server.bidAuction(threaduser, id, amount);
								
								if (ret.equals("ended"))
									send("The auction with id "+id+" has already been ended!");
								else if (ret.equals(""))
									send("There is no current available auction with id: "+id+".");
								else
								{								
									s = ret.split(";");
									
									if(threaduser.equals(s[0]) && (amount == Double.valueOf(s[1])))
										send("You successfully bid with "+amount+" on '"+s[2]+"'."); 	
									else
										send("You unsuccessfully bid with "+amount+" on '"+s[2]+"'. Current highest bid is "+s[1]);
								}								 
								 
							}
							else 
								send("Usage: !bid <auction-id> <amount> - the id has to be a number, and the amount a float with a '.' as separator! ");							
						}
						else
							send("Usage: !bid <auction-id> <amount>");
					}
				}			
				
				
				//read new command
				command = in.readLine();
				if (command != null){
					temp = command.split(";")[0];
					command = temp;
				}							
				
			}while(command != null);
			
			cleanUp();
		} catch (IOException e) {
			System.out.println("Client error.");
			cleanUp();
			Server.removeClient(this);
		}
	}

	private void cleanUp() {
		try {
			if (out != null) {
				out.close();
			}
			if (in != null) {
				out.close();
			}
			socket.close();
		} catch (IOException e) {
			/* ignore */
		}
	}

	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		final ClientThread other = (ClientThread) obj;
		if (socket == null) {
			if (other.socket != null) {
				return false;
			}
		} else if (!socket.equals(other.socket)) {
			return false;
		}
		return true;
	}

	public void send(String message) {
		out.println(message);
	}

	public String getUsername() {
		return this.threaduser;
	}
}
